#include <stdio.h>
#include <glib.h>


// ref: https://www.cnblogs.com/tears-of-ramos/p/3929175.html
// tip: glib简单记录包括字符串，主循环，回调函数和xml解析 


/**
 * 自定义的事件源是一个继承 GSource 的结构体,即自定义事件源的结构体 的第一个成员是 GSource 结构体, 其后便可放置程序所需数据, 例如:
 */
typedef struct {
    GSource source;
    gchar text[256];
} MySource;


/**
 * 实现了事件源数据结构的定义之后,还需要实现事件源所规定的接口,
 * 主要为 prepare, check, dispatch, finalize 等事件处理函数(回调函数),它们包含于 GSourceFuncs 结构体中。
 * 将 GSourceFuncs结构以及事件源结构的存储空间宽度作为参数传给 g_source_new 便可构造一个新的事件源,
 * 继而可使用 g_source_attach 函数将新的事件源添加到主循环上下文中
 */
static gboolean prepare(GSource* source, gint* timeout)
{
    *timeout = 0;

    return TRUE;
}



static gboolean check(GSource *source)
{
    return TRUE;
}



static gboolean dispatch(GSource* source, GSourceFunc callback, gpointer user_data)
{
	static int i = 0;
	g_print("%s %d\n", ((MySource*) source)->text, ++i);
    return TRUE;
}


/** 
 * g_main_loop_run 函数运行时,会迭代访问 GMainContext 的事件源列表,步骤大致如下:
 * 
 * a. g_main_loop_run 通过调用事件源的 prepare 接口并判断其返回值以确定各事件源是否作好准备。
 * 	如果各事件源的 prepare 接口的返回值为 TRUE,即表示该事件源已经作好准备,
 * 	否则表示尚未做好准备。显然,上述程序所定义的事件源是已经作好了准备。
 * 	
 * b. 若某事件源尚未作好准备 ,那么 g_main_loop 会在处理完那些已经准备好的事件后再次询问该事件源是否作好准备 ,
 * 	这一过程是通过调用事件源的 check 接口而实现的,如果事件源依然未作好准备,
 * 	即 check 接口的返回 FALSE,那么 g_main_loop_run 会让主事件循环进入睡眠状态。
 * 
 * 主事件循环的睡眠时间是步骤 a 中遍历时间源时所统计的最小时间间隔 ,
 * 例如在 prepare 接口中可以像下面这样设置时间间隔。
 * 到达一定时间后, g_main_loop_run 会唤醒主事件循环,
 * 再次询问。如此周而复始,直至事件源的 prepare 接口返回值为 TRUE。
 */
int main()
{
    GMainLoop* 		loop 			= g_main_loop_new(NULL, TRUE);
    GMainContext* 	context 		= g_main_loop_get_context(loop);
    GSourceFuncs 	source_funcs 	= {prepare, check, dispatch, NULL};
    GSource*		source 			= g_source_new(&source_funcs, sizeof(MySource));
	
	
	
    sprintf(((MySource *)source)->text, "Hello world");

    //g_timeout_add(100, timeout_func, loop);
	
	// 添加事件源
    g_source_attach(source, context);	
    g_source_unref(source);

    g_main_loop_run(loop);

    g_main_context_unref(context);
    g_main_loop_unref(loop);

    return 0;
}


/*
# 通用一点的Makefile

CC = gcc
CFLAGS = -g -Wall `pkg-config --libs --cflags glib-2.0`

# make NAME=2021_07_26_test_loop
NAME ?= 2021_07_26_test_loop

run: $(NAME)
	@./$(NAME)

$(NAME): $(NAME).c
	@$(CC) -o $@ $^ $(CFLAGS) 
	
clean:
	rm $(NAME)
*/